package com.zhonghui.wms.service.impl;

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;

import com.zhonghui.common.utils.DateUtils;
import com.zhonghui.common.utils.SecurityUtils;
import com.zhonghui.mes.domain.MesMaterialApply;
import com.zhonghui.mes.domain.vo.MesMaterialApplyVo;
import com.zhonghui.mes.domain.vo.MesProductionCompletionVo;
import com.zhonghui.mes.mapper.MesMaterialApplyMapper;
import com.zhonghui.mes.service.IMesMaterialApplyService;
import com.zhonghui.scm.domain.ScmPurchaseArrival;
import com.zhonghui.scm.domain.ScmSaleDelivery;
import com.zhonghui.scm.domain.ScmSaleReturn;
import com.zhonghui.scm.mapper.ScmSaleDeliveryMapper;
import com.zhonghui.wms.domain.vo.*;
import com.zhonghui.wms.mapper.*;
import com.zhonghui.wms.service.IWmsMaterialInventoryService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import com.zhonghui.common.utils.StringUtils;
import org.springframework.transaction.annotation.Transactional;
import com.zhonghui.wms.domain.WmsOutboundApplicationDetails;
import com.zhonghui.wms.domain.WmsOutboundApplication;
import com.zhonghui.wms.service.IWmsOutboundApplicationService;

import static com.zhonghui.framework.datasource.DynamicDataSourceContextHolder.log;

/**
 * 智能仓储WMS-出库申请Service业务层处理
 *
 * @author zhonghui
 * @date 2023-08-08
 */
@Service
public class WmsOutboundApplicationServiceImpl implements IWmsOutboundApplicationService
{
    @Autowired
    private WmsOutboundApplicationMapper wmsOutboundApplicationMapper;

    @Autowired
    private WmsOutboundApplicationDetailsMapper wmsOutboundApplicationDetailsMapper;

    @Autowired
    private WmsInventoryDetailsMapper wmsInventoryDetailsMapper;

    @Autowired
    private MesMaterialApplyMapper mesMaterialApplyMapper;

    @Autowired
    private ScmSaleDeliveryMapper scmSaleDeliveryMapper;

    @Autowired
    private WmsWarehouseMapper wmsWarehouseMapper;

    @Autowired
    private WmsWarehouseAreaMapper wmsWarehouseAreaMapper;

    @Autowired
    private WmsMaterialMapper wmsMaterialMapper;

    @Autowired
    private IWmsMaterialInventoryService wmsMaterialInventoryService;

    @Autowired
    private IMesMaterialApplyService mesMaterialApplyService;

    /**
     * 查询智能仓储WMS-出库申请
     *
     * @param id 智能仓储WMS-出库申请主键
     * @return 智能仓储WMS-出库申请
     */
    @Override
    public WmsOutboundApplicationVo selectWmsOutboundApplicationById(Long id)
    {
        WmsOutboundApplicationVo wmsOutboundApplicationVo = wmsOutboundApplicationMapper.selectWmsOutboundApplicationById(id);
        for (WmsOutboundApplicationDetails details:wmsOutboundApplicationVo.getWmsOutboundApplicationDetailsList()) {
            // 遍历指定仓库中的库区和库位列表，用于前端查询是数据的回显
            details.setWmsWarehouseAreaList(wmsWarehouseMapper.selectWmsWarehouseById(details.getWarehouseId()).getWmsWarehouseAreaList());
            details.setWmsWarehouseSeatList(wmsWarehouseAreaMapper.selectWmsWarehouseAreaById(details.getWarehouseAreaId()).getWmsWarehouseSeatList());
            // 获取物料信息
            details.setMaterialName(wmsMaterialMapper.selectWmsMaterialById(details.getMaterialId()).getMaterialName());
            details.setMaterialCode(wmsMaterialMapper.selectWmsMaterialById(details.getMaterialId()).getMaterialCode());
            details.setMaterialPrice(wmsMaterialMapper.selectWmsMaterialById(details.getMaterialId()).getMaterialPrice());
            details.setMaterialUnit(wmsMaterialMapper.selectWmsMaterialById(details.getMaterialId()).getMaterialUnit());
            details.setMaterialSpecification(wmsMaterialMapper.selectWmsMaterialById(details.getMaterialId()).getMaterialSpecifications());
            details.setMaterialModel(wmsMaterialMapper.selectWmsMaterialById(details.getMaterialId()).getMaterialModel());
        }
        // 关联单据号
        getAssociationDocumentNo(wmsOutboundApplicationVo);
        return wmsOutboundApplicationVo;
    }

    /**
     * 查询智能仓储WMS-出库申请列表
     *
     * @param wmsOutboundApplicationVo 智能仓储WMS-出库申请
     * @return 智能仓储WMS-出库申请
     */
    @Override
    public List<WmsOutboundApplicationVo> selectWmsOutboundApplicationList(WmsOutboundApplicationVo wmsOutboundApplicationVo)
    {
        // 查询出库申请列表
        List<WmsOutboundApplicationVo> list = wmsOutboundApplicationMapper.selectWmsOutboundApplicationList(wmsOutboundApplicationVo);
        list.stream().forEach(item ->{
            // 调用获取关联单据号方法
            getAssociationDocumentNo(item);
        });
        return list;
    }
    private void getAssociationDocumentNo(WmsOutboundApplicationVo wmsOutboundApplicationVo) {
        //领料申请出库
        if(wmsOutboundApplicationVo.getBusinessType() == 1) {
            //获取领料单号
            MesMaterialApplyVo apply = mesMaterialApplyMapper.selectMesMaterialApplyById(wmsOutboundApplicationVo.getDocumentNoId());
            if(apply != null) {
                wmsOutboundApplicationVo.setAssociationDocumentNo(apply.getOddNumber());
            }
        }
        //销售发货出库
        if(wmsOutboundApplicationVo.getBusinessType() == 2) {
            ScmSaleDelivery delivery = scmSaleDeliveryMapper.getById(wmsOutboundApplicationVo.getDocumentNoId());
            if(delivery != null) {
                wmsOutboundApplicationVo.setAssociationDocumentNo(delivery.getDeliveryNo());
                wmsOutboundApplicationVo.setContractNumber(delivery.getContractNo());
            }
        }
    }
    /**
     * 新增智能仓储WMS-出库申请
     *
     * @param wmsOutboundApplicationVo 智能仓储WMS-出库申请
     * @return 结果
     */
    @Transactional
    @Override
    public int insertWmsOutboundApplication(WmsOutboundApplicationVo wmsOutboundApplicationVo)
    {
        String documentNo = generateNumber("CKSQ");
        wmsOutboundApplicationVo.setDocumentNo(documentNo);
        // 出库状态: 0未出库1已出库
        wmsOutboundApplicationVo.setDocumentStatus(Long.parseLong("0"));
        // 申请类型：1入库单2出库单
        wmsOutboundApplicationVo.setApplicationType(Long.parseLong("2"));
        // 申请人，申请时间
        wmsOutboundApplicationVo.setApplicant(SecurityUtils.getLoginUser().getUserId());
        wmsOutboundApplicationVo.setApplicationDate(DateUtils.getNowDate());
        // 更新领料申请
        if (wmsOutboundApplicationVo.getBusinessType() == 1) {
            // 更新关联单状态
            updateAssociationStatus(wmsOutboundApplicationVo.getBusinessType(),wmsOutboundApplicationVo.getDocumentNoId(),Long.parseLong("1"));
        }
        // 更新销售发货
        if (wmsOutboundApplicationVo.getBusinessType() == 2) {
            // 更新关联单状态
            updateAssociationStatus(wmsOutboundApplicationVo.getBusinessType(),wmsOutboundApplicationVo.getDocumentNoId(),Long.parseLong("1"));
        }
        int rows = wmsOutboundApplicationMapper.insertWmsOutboundApplication(wmsOutboundApplicationVo);
        insertWmsOutboundApplicationDetails(wmsOutboundApplicationVo);
        return rows;
    }
    private String generateNumber(String number){
        Date date = new Date();
        SimpleDateFormat format = new SimpleDateFormat("yyyyMMddHHmmssSSS");
        return number+format.format(date);
    }
    /**
     * 修改智能仓储WMS-出库申请
     *
     * @param wmsOutboundApplicationVo 智能仓储WMS-出库申请
     * @return 结果
     */
    @Transactional
    @Override
    public int updateWmsOutboundApplication(WmsOutboundApplicationVo wmsOutboundApplicationVo)
    {
        if (wmsOutboundApplicationVo.getApprovedStatus() == null) {
            wmsOutboundApplicationMapper.deleteWmsOutboundApplicationDetailsByOutboundApplicationId(wmsOutboundApplicationVo.getId());
            insertWmsOutboundApplicationDetails(wmsOutboundApplicationVo);
        }
        // 更新关联单状态
        updateAssociationStatus(wmsOutboundApplicationVo.getBusinessType(),wmsOutboundApplicationVo.getDocumentNoId(),Long.parseLong("1"));
        return wmsOutboundApplicationMapper.updateWmsOutboundApplication(wmsOutboundApplicationVo);
    }
    /**
     * 更新关联单状态
     */
    private void updateAssociationStatus(Long businessType, Long documentNoId, Long status) {
        // 更新领料申请 1领料出库
        if (businessType == 1){
            MesMaterialApplyVo applyVo = mesMaterialApplyMapper.selectMesMaterialApplyById(documentNoId);
            if (applyVo != null){
                applyVo.setStatus(Integer.parseInt(String.valueOf(status)));
                mesMaterialApplyMapper.updateMesMaterialApply(applyVo);
            }
        }
        // 更新销售发货 2发货出库
        if (businessType == 2){
            ScmSaleDelivery delivery = scmSaleDeliveryMapper.getById(documentNoId);
            if (delivery != null) {
                // 更新销售发货单状态
                delivery.setStatus(Integer.parseInt(String.valueOf(status)));
                scmSaleDeliveryMapper.edit(delivery);
            }
        }
    }

    /**
     * 批量删除智能仓储WMS-出库申请
     *
     * @param ids 需要删除的智能仓储WMS-出库申请主键
     * @return 结果
     */
    @Transactional
    @Override
    public int deleteWmsOutboundApplicationByIds(Long[] ids)
    {
        wmsOutboundApplicationMapper.deleteWmsOutboundApplicationDetailsByOutboundApplicationIds(ids);
        return wmsOutboundApplicationMapper.deleteWmsOutboundApplicationByIds(ids);
    }

    /**
     * 删除智能仓储WMS-出库申请信息
     *
     * @param id 智能仓储WMS-出库申请主键
     * @return 结果
     */
    @Transactional
    @Override
    public int deleteWmsOutboundApplicationById(Long id)
    {
        wmsOutboundApplicationMapper.deleteWmsOutboundApplicationDetailsByOutboundApplicationId(id);
        return wmsOutboundApplicationMapper.deleteWmsOutboundApplicationById(id);
    }

    /**
     * 新增智能仓储WMS-出库申请明细信息
     *
     * @param wmsOutboundApplicationVo 智能仓储WMS-出库申请对象
     */
    public void insertWmsOutboundApplicationDetails(WmsOutboundApplicationVo wmsOutboundApplicationVo)
    {
        List<WmsOutboundApplicationDetails> wmsOutboundApplicationDetailsList = wmsOutboundApplicationVo.getWmsOutboundApplicationDetailsList();
        Long id = wmsOutboundApplicationVo.getId();
        if (StringUtils.isNotNull(wmsOutboundApplicationDetailsList))
        {
            List<WmsOutboundApplicationDetails> list = new ArrayList<WmsOutboundApplicationDetails>();
            for (WmsOutboundApplicationDetails wmsOutboundApplicationDetails : wmsOutboundApplicationDetailsList)
            {
                wmsOutboundApplicationDetails.setOutboundApplicationId(id);
                list.add(wmsOutboundApplicationDetails);
            }
            if (list.size() > 0)
            {
                wmsOutboundApplicationMapper.batchWmsOutboundApplicationDetails(list);
            }
        }
    }

    /**
     * 执行出库
     * @param id 出库申请主键id
     */
    @Transactional
    @Override
    public void executeOutbound(Long id) {
        WmsOutboundApplicationDetails woaDetails = new WmsOutboundApplicationDetails();
        woaDetails.setOutboundApplicationId(id);
        // 查询出库明细
        List<WmsOutboundApplicationDetails> applyDetail = wmsOutboundApplicationDetailsMapper
                .selectWmsOutboundApplicationDetailsList(woaDetails);
        // 循环遍历出库明细
        applyDetail.stream().forEach(detail -> {
            // 构建查询条件
            WmsInventoryDetailsVo wiDetailsVo = new WmsInventoryDetailsVo();
            wiDetailsVo.setWarehouseId(detail.getWarehouseId());
            wiDetailsVo.setWarehouseAreaId(detail.getWarehouseAreaId());
            wiDetailsVo.setWarehouseSeatId(detail.getWarehouseSeatId());
            wiDetailsVo.setMaterialId(detail.getMaterialId());
            wiDetailsVo.setBatchNumber(detail.getBatchNumber());
            // 根据以上条件查询物料库存明细中是否包含该物料
            List<WmsInventoryDetailsVo> wmInventoryVoList = wmsInventoryDetailsMapper
                    .selectWmsInventoryDetailsList(wiDetailsVo);
            if (wmInventoryVoList != null && !wmInventoryVoList.isEmpty()) {
                WmsInventoryDetailsVo material = wmInventoryVoList.get(0);
                double total = material.getExistingInventory() == null ? 0 : material.getExistingInventory();
                double lock = material.getLockInventory() == null ? 0 : material.getLockInventory();
                // 现有库存=总库存-锁定库存
                double inventory = total - lock;
                // 出库量
                double outInventory = detail.getOutboundNumber() == null ? 0 : detail.getOutboundNumber();
                // 实际出库量
                double factOutInventory = Math.min(inventory, outInventory);
                // 更新库位总库存
                material.setExistingInventory(inventory - factOutInventory);
                wmsInventoryDetailsMapper.updateWmsInventoryDetails(material);
                // 更新目标仓库总库存
                wmsMaterialInventoryService.updateMaterialTotalInventory(material.getInventoryId());
            }
        });
        // 更新出库单状态为已拣货
        WmsOutboundApplicationVo applyVo = wmsOutboundApplicationMapper.selectWmsOutboundApplicationById(id);
        applyVo.setDocumentStatus(Long.parseLong("1"));
        wmsOutboundApplicationMapper.updateWmsOutboundApplication(applyVo);
    }

    @Transactional
    @Override
    public void executeDelivery(Long id) {
        WmsOutboundApplicationVo applyVo = wmsOutboundApplicationMapper.selectWmsOutboundApplicationById(id);
        // 领料出库
        if (applyVo.getBusinessType() == 1) {
            deliveryProduct(applyVo);
        }
        // 销售出库生成承运单
        if (applyVo.getBusinessType() ==2) {
            deliverySale(applyVo);
        }
        // 更新出库单状态
        applyVo.setDocumentStatus(Long.parseLong("3"));
        wmsOutboundApplicationMapper.updateWmsOutboundApplication(applyVo);
    }

    private void deliveryProduct(WmsOutboundApplicationVo applyVo) {
        // 更新物料已领数量
        MesMaterialApplyVo mesMaterialApplyVo = mesMaterialApplyMapper.selectMesMaterialApplyById(applyVo.getDocumentNoId());
        // 判断关联单据明细是否与出库明细一致
        mesMaterialApplyVo.getMesMaterialApplyItemList().stream().forEach(item -> {
            // 设置已领数量
            item.setReceivedQuantity(item.getDosage());
        });
        // 更新领料单状态为已领料
        mesMaterialApplyVo.setStatus(Integer.parseInt(String.valueOf(2)));
        mesMaterialApplyService.checkMesMaterialApply(mesMaterialApplyVo);
    }

    /**
     * 销售发货
     * @param applyVo
     */
    private void deliverySale(WmsOutboundApplicationVo applyVo) {
        // 获取出库申请明细
        List<WmsOutboundApplicationDetails> applyDetailList = applyVo.getWmsOutboundApplicationDetailsList();
        ScmSaleDelivery saleDelivery = scmSaleDeliveryMapper.getById(applyVo.getDocumentNoId());

        // 判断承运申请明细是否为空
        if (applyDetailList == null || applyDetailList.isEmpty()) {
            log.error("出库单：单据号[{}]，id[{}]；没有找到出库物料明细！", applyVo.getDocumentNo(), applyVo.getId());
        }
        // 更新销售发货单为已出库
        updateAssociationStatus(applyVo.getBusinessType(), applyVo.getDocumentNoId(), Long.parseLong("2"));
    }

}
